package com.zxiw.zxedu.recyclerview.group

import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ExpandableListView.OnChildClickListener
import androidx.annotation.CallSuper
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.zxiw.zxedu.recyclerview.XRecyclerView
import com.zxiw.zxedu.recyclerview.adapter.HelperRecyclerViewHolder


/**
 * @author zhangxiaoming
 * @date 2023/8/18
 * @description 适配器分组
 * 通用的分组列表Adapter。通过它可以很方便的实现列表的分组效果。
 * 这个类提供了一系列的对列表的更新、删除和插入等操作的方法。
 * 使用者要使用这些方法的列表进行操作，而不要直接使用RecyclerView.Adapter的方法。
 * 因为当分组列表发生变化时，需要及时更新分组列表的组结构{@link GroupedRecyclerViewAdapter#mStructures}
 * <p>
 * 1.增加了对XRecyclerView兼容
 * 2.增加了对子项分组支持，主要是针对GridLayoutManager,动态设置getSpanSize，需要覆写getChildSpanSize
 */
@SuppressLint("NotifyDataSetChanged")
abstract class GroupedRecyclerViewAdapter<T>(val context: Context) :
    RecyclerView.Adapter<HelperRecyclerViewHolder>() {
    private val mGroups: MutableList<T> = mutableListOf()

    private var mOnHeaderClickListener: OnHeaderClickListener<T>? = null
    private var mOnFooterClickListener: OnFooterClickListener<T>? = null
    private var mOnChildClickListener: OnChildClickListener<T>? = null

    //保存分组列表的组结构
    protected var mStructures: ArrayList<GroupStructure> = ArrayList()

    //数据是否发生变化。如果数据发生变化，要及时更新组结构。
    private var isDataChanged = false
    private var mTempPosition = 0
    protected var xRecyclerView: XRecyclerView? = null

    init {
        registerAdapterDataObserver(GroupDataObserver())
    }

    companion object {
        const val TYPE_HEADER = 50000
        const val TYPE_FOOTER = 50001
        const val TYPE_CHILD = 50002
    }

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        val manager = recyclerView.layoutManager
        xRecyclerView = if (recyclerView is XRecyclerView) recyclerView else null
        if (manager is GridLayoutManager) {
            manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                override fun getSpanSize(position: Int): Int {
                    if (xRecyclerView != null) {//说明是XRecyclerView布局，XRecyclerView有头和尾需要进一步做特殊处理
                        return if (xRecyclerView!!.isHeaderFooter(position)) manager.spanCount else getGridSpanSize(
                            position - (xRecyclerView!!.getHeadersCount() + 1)
                        )
                    } else { //说明是普通的RecyclerView布局
                        return getGridSpanSize(position)
                    }
                }

                fun getGridSpanSize(position: Int): Int {
                    val count = manager.spanCount
                    val type = judgeType(position)
                    //只对子项做Grid效果
                    if (type == TYPE_CHILD) {
                        val groupPosition = getGroupPositionForPosition(position)
                        val childPosition = getChildPositionForPosition(groupPosition, position)
                        return getChildSpanSize(groupPosition, childPosition)
                    }
                    return count
                }
            }
        }
        structureChanged()
    }

    /**
     * 提供这个方法可以使外部改变子项的SpanSize。只有在GridLayoutManager下才起作用，也就是Gride子分组的情况下
     * 这个方法的作用跟{@link (GridLayoutManager.SpanSizeLookup)#getSpanSize(int)}一样。
     *
     * @param groupPosition
     * @param childPosition
     */
    fun getChildSpanSize(groupPosition: Int, childPosition: Int): Int {
        return 1 //默认就是1列
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HelperRecyclerViewHolder {
        val layoutId: Int = getLayoutId(mTempPosition, viewType)
        val view = LayoutInflater.from(context).inflate(layoutId, parent, false)
        return HelperRecyclerViewHolder(view, layoutId)
    }

    override fun onBindViewHolder(holder: HelperRecyclerViewHolder, position: Int) {
        val type = judgeType(position)
        val groupPosition = getGroupPositionForPosition(position)
        val group: T = mGroups[groupPosition]
        when (type) {
            TYPE_HEADER -> {
                mOnHeaderClickListener?.let {
                    holder.itemView.setOnClickListener { _ ->
                        it.onHeaderClick(
                            this,
                            holder,
                            groupPosition,
                            group
                        )
                    }
                }
                onBindHeaderViewHolder(holder, groupPosition, group)
            }
            TYPE_FOOTER -> {
                mOnFooterClickListener?.let {
                    holder.itemView.setOnClickListener { _ ->
                        it.onFooterClick(this, holder, groupPosition, group)
                    }
                }
                onBindFooterViewHolder(holder, groupPosition, group)
            }
            TYPE_CHILD -> {
                val childPosition = getChildPositionForPosition(groupPosition, position)
                mOnChildClickListener?.let {
                    holder.itemView.setOnClickListener { _ ->
                        it.onChildClick(this, holder, groupPosition, childPosition, group)
                    }
                }
                onBindChildViewHolder(holder, groupPosition, childPosition, group)
            }
        }
    }

    override fun onBindViewHolder(
        holder: HelperRecyclerViewHolder,
        position: Int,
        payloads: MutableList<Any>
    ) {
        if (payloads.isEmpty()) {// payloads 为 空，说明是更新整个 ViewHolder
            onBindViewHolder(holder, position)
        } else {// payloads 不为空，这只更新需要更新的 View 即可。
            super.onBindViewHolder(holder, position, payloads)
        }
    }

    override fun getItemCount(): Int {
        return itemCount()
    }

    protected fun itemCount(): Int {
        if (isDataChanged) {
            structureChanged()
        }
        return count()
    }

    override fun getItemViewType(position: Int): Int {
        mTempPosition = position
        val groupPosition = getGroupPositionForPosition(position)
        return when (judgeType(position)) {
            TYPE_HEADER -> getHeaderViewType(groupPosition)
            TYPE_FOOTER -> getFooterViewType(groupPosition)
            TYPE_CHILD -> {
                val childPosition = getChildPositionForPosition(groupPosition, position)
                val childType = getChildViewType(groupPosition, childPosition)
                childType
            }
            else -> super.getItemViewType(position)
        }
    }

    open fun getHeaderViewType(groupPosition: Int): Int {
        return TYPE_HEADER
    }

    open fun getFooterViewType(groupPosition: Int): Int {
        return TYPE_FOOTER
    }

    open fun getChildViewType(groupPosition: Int, childPosition: Int): Int {
        return TYPE_CHILD
    }

    private fun getLayoutId(position: Int, viewType: Int): Int {
        val type = judgeType(position)
        return when (type) {
            TYPE_HEADER -> getHeaderLayout(viewType)
            TYPE_FOOTER -> getFooterLayout(viewType)
            TYPE_CHILD -> getChildLayout(viewType)
            else -> 0
        }
    }

    private fun count(): Int {
        return countGroupRangeItem(0, mStructures.size)
    }

    @CallSuper
    open fun setGroups(datas: List<T>): Boolean {
        mGroups.clear()
        var result = false
        if (datas.isNotEmpty()) {
            result = mGroups.addAll(datas)
        }
        structureChanged();
        notifyDataSetChanged();
        return result
    }

    fun addGroups(datas: List<T>): Boolean {
        var result = false
        if (datas.isNotEmpty()) {
            result = mGroups.addAll(datas)
        }
        structureChanged()
        notifyDataSetChanged()
        return result
    }

    fun addGroup(data: T): Boolean {
        var result = mGroups.add(data)
        structureChanged()
        notifyDataSetChanged()
        return result
    }

    fun getGroup(groupPosition: Int): T {
        return mGroups.get(groupPosition)
    }

    fun getGroups(): List<T> {
        return mGroups
    }

    /**
     * 判断item的type 头部 尾部 和 子项
     */
    fun judgeType(position: Int): Int {
        var itemCount = 0
        val groupCount = mStructures.size
        for (i in 0 until groupCount) {
            val structure = mStructures[i]
            if (structure.hasHeader) {
                itemCount += 1
                if (position < itemCount) {
                    return TYPE_HEADER
                }
            }
            itemCount += structure.childrenCount
            if (position < itemCount) {
                return TYPE_CHILD
            }
            if (structure.hasFooter) {
                itemCount += 1
                if (position < itemCount) {
                    return TYPE_FOOTER
                }
            }
        }
        return 0
    }

    /**
     * 重置组结构列表
     */
    private fun structureChanged() {
        mStructures.clear()
        val groupCount = getGroupCount()
        for (i in 0 until groupCount) {
            mStructures.add(GroupStructure(hasHeader(i), hasFooter(i), getChildrenCount(i)))
        }
        isDataChanged = false
    }

    /**
     * 根据下标计算position所在的组（groupPosition）
     *
     * @param position 下标
     * @return 组下标 groupPosition
     */
    fun getGroupPositionForPosition(position: Int): Int {
        var count = 0
        val groupCount = mStructures.size
        for (i in 0 until groupCount) {
            count += countGroupItem(i)
            if (position < count) {
                return i
            }
        }
        return -1
    }

    /**
     * 根据下标计算position在组中位置（childPosition）
     *
     * @param groupPosition 所在的组
     * @param position      下标
     * @return 子项下标 childPosition
     */
    fun getChildPositionForPosition(groupPosition: Int, position: Int): Int {
        if (groupPosition < mStructures.size) {
            val itemCount = countGroupRangeItem(0, groupPosition + 1)
            val structure = mStructures[groupPosition]
            val p =
                structure.childrenCount - (itemCount - position) + if (structure.hasFooter) 1 else 0
            if (p >= 0) {
                return p
            }
        }
        return -1
    }

    /**
     * 获取一个组的组头下标 如果该组没有组头 返回-1
     *
     * @param groupPosition 组下标
     * @return 下标
     */
    fun getPositionForGroupHeader(groupPosition: Int): Int {
        if (groupPosition < mStructures.size) {
            val structure = mStructures.get(groupPosition)
            if (!structure.hasHeader) {
                return -1
            }
            return countGroupRangeItem(0, groupPosition)
        }
        return -1
    }

    /**
     * 获取一个组的组尾下标 如果该组没有组尾 返回-1
     *
     * @param groupPosition 组下标
     * @return 下标
     */
    fun getPositionForGroupFooter(groupPosition: Int): Int {
        if (groupPosition < mStructures.size) {
            val structure = mStructures[groupPosition]
            return if (!structure.hasFooter) {
                -1
            } else countGroupRangeItem(0, groupPosition + 1) - 1
        }
        return -1
    }

    /**
     * 获取一个组指定的子项下标 如果没有 返回-1
     *
     * @param groupPosition 组下标
     * @param childPosition 子项的组内下标
     * @return 下标
     */
    fun getPositionForChild(groupPosition: Int, childPosition: Int): Int {
        if (groupPosition < mStructures.size) {
            val structure = mStructures[groupPosition]
            if (structure.childrenCount > childPosition) {
                val itemCount: Int = countGroupRangeItem(0, groupPosition)
                return itemCount + childPosition + if (structure.hasHeader) 1 else 0
            }
        }
        return -1
    }

    /**
     * 计算一个组里有多少个Item（头加尾加子项）
     */
    fun countGroupItem(groupPosition: Int): Int {
        var itemCount = 0
        if (groupPosition < mStructures.size) {
            val structure = mStructures[groupPosition]
            if (structure.hasHeader) {
                itemCount += 1
            }
            itemCount += structure.childrenCount
            if (structure.hasFooter) {
                itemCount += 1
            }
        }
        return itemCount
    }

    /**
     * 计算多个组的项的总和
     */
    fun countGroupRangeItem(start: Int, count: Int): Int {
        var itemCount = 0
        val size = mStructures.size
        var i = start
        while (i < size && i < start + count) {
            itemCount += countGroupItem(i)
            i++
        }
        return itemCount
    }

    /**
     * 刷新数据列表
     */
    fun changeDataSet() {
        isDataChanged = true
        notifyDataSetChanged()
    }

    /**
     * 刷新一组数据，包括组头,组尾和子项
     */
    fun changeGroup(groupPosition: Int) {
        val index = getPositionForGroupHeader(groupPosition)
        val itemCount = countGroupItem(groupPosition)
        if (index >= 0 && itemCount > 0) {
            notifyItemRangeChanged(index, itemCount)
        }
    }

    /**
     * 刷新多组数据，包括组头,组尾和子项
     */
    fun changeRangeGroup(groupPosition: Int, count: Int) {
        val index = getPositionForGroupHeader(groupPosition)
        var itemCount = 0
        itemCount = if (groupPosition + count <= mStructures.size) {
            countGroupRangeItem(groupPosition, groupPosition + count)
        } else {
            countGroupRangeItem(groupPosition, mStructures.size)
        }
        if (index >= 0 && itemCount > 0) {
            notifyItemRangeChanged(index, itemCount)
        }
    }

    /**
     * 刷新组头
     */
    fun changeHeader(groupPosition: Int) {
        val index = getPositionForGroupHeader(groupPosition)
        if (index >= 0) {
            notifyItemChanged(index)
        }
    }

    /**
     * 刷新组尾
     */
    fun changeFooter(groupPosition: Int) {
        val index = getPositionForGroupFooter(groupPosition)
        if (index >= 0) {
            notifyItemChanged(index)
        }
    }

    /**
     * 刷新一组里的某个子项
     */

    fun changeChild(groupPosition: Int, childPosition: Int) {
        val index = getPositionForChild(groupPosition, childPosition)
        if (index >= 0) {
            notifyItemChanged(index)
        }
    }

    /**
     * 刷新一组里的多个子项
     */
    fun changeRangeChild(groupPosition: Int, childPosition: Int, count: Int) {
        if (groupPosition < mStructures.size) {
            val index = getPositionForChild(groupPosition, childPosition)
            if (index >= 0) {
                val (_, _, childrenCount) = mStructures[groupPosition]
                if (childrenCount >= childPosition + count) {
                    notifyItemRangeChanged(index, count)
                } else {
                    notifyItemRangeChanged(index, childrenCount - childPosition)
                }
            }
        }
    }

    /**
     * 刷新一组里的所有子项
     */
    fun changeChildren(groupPosition: Int) {
        if (groupPosition < mStructures.size) {
            val index = getPositionForChild(groupPosition, 0)
            if (index >= 0) {
                val (_, _, childrenCount) = mStructures[groupPosition]
                notifyItemRangeChanged(index, childrenCount)
            }
        }
    }


    /**
     * 删除所有数据
     */
    @CallSuper
    open fun removeAll() {
        notifyItemRangeRemoved(0, itemCount)
        mStructures.clear()
    }

    /**
     * 删除一组数据，包括组头,组尾和子项
     */
    @CallSuper
    open fun removeGroup(groupPosition: Int) {
        val index = getPositionForGroupHeader(groupPosition)
        val itemCount = countGroupItem(groupPosition)
        if (index >= 0 && itemCount > 0) {
            notifyItemRangeRemoved(index, itemCount)
            notifyItemRangeChanged(index, getItemCount() - itemCount)
            mStructures.removeAt(groupPosition)
        }
    }

    /**
     * 删除多组数据，包括组头,组尾和子项
     */
    @CallSuper
    open fun removeRangeGroup(groupPosition: Int, count: Int) {
        val index = getPositionForGroupHeader(groupPosition)
        var itemCount = 0
        itemCount = if (groupPosition + count <= mStructures.size) {
            countGroupRangeItem(groupPosition, groupPosition + count)
        } else {
            countGroupRangeItem(groupPosition, mStructures.size)
        }
        if (index >= 0 && itemCount > 0) {
            notifyItemRangeRemoved(index, itemCount)
            notifyItemRangeChanged(index, getItemCount() - itemCount)
            mStructures.removeAt(groupPosition)
        }
    }

    /**
     * 删除组头
     */
    fun removeHeader(groupPosition: Int) {
        val index = getPositionForGroupHeader(groupPosition)
        if (index >= 0) {
            val structure = mStructures[groupPosition]
            notifyItemRemoved(index)
            notifyItemRangeChanged(index, itemCount - index)
            structure.hasHeader = false
        }
    }

    /**
     * 删除组尾
     */
    fun removeFooter(groupPosition: Int) {
        val index = getPositionForGroupFooter(groupPosition)
        if (index >= 0) {
            val structure = mStructures[groupPosition]
            notifyItemRemoved(index)
            notifyItemRangeChanged(index, itemCount - index)
            structure.hasFooter = false
        }
    }

    /**
     * 删除一组里的某个子项
     */
    fun removeChild(groupPosition: Int, childPosition: Int) {
        val index = getPositionForChild(groupPosition, childPosition)
        if (index >= 0) {
            val structure = mStructures[groupPosition]
            notifyItemRemoved(index)
            notifyItemRangeChanged(index, itemCount - index)
            structure.childrenCount = structure.childrenCount - 1
        }
    }

    /**
     * 删除一组里的多个子项
     */
    fun removeRangeChild(groupPosition: Int, childPosition: Int, count: Int) {
        if (groupPosition < mStructures.size) {
            val index = getPositionForChild(groupPosition, childPosition)
            if (index >= 0) {
                val structure = mStructures[groupPosition]
                val childCount = structure.childrenCount
                var removeCount = count
                if (childCount < childPosition + count) {
                    removeCount = childCount - childPosition
                }
                notifyItemRangeRemoved(index, removeCount)
                notifyItemRangeChanged(index, itemCount - removeCount)
                structure.childrenCount = childCount - removeCount
            }
        }
    }

    /**
     * 删除一组里的所有子项
     */
    fun removeChildren(groupPosition: Int) {
        if (groupPosition < mStructures.size) {
            val index = getPositionForChild(groupPosition, 0)
            if (index >= 0) {
                val structure = mStructures[groupPosition]
                val itemCount = structure.childrenCount
                notifyItemRangeRemoved(index, itemCount)
                notifyItemRangeChanged(index, getItemCount() - itemCount)
                structure.childrenCount = 0
            }
        }
    }

    //****** 插入操作 *****//

    //****** 插入操作 *****//
    /**
     * 插入一组数据
     *
     * @param groupPosition
     */
    @CallSuper
    open fun insertGroup(groupPosition: Int) {
        var groupPosition = groupPosition
        val structure = GroupStructure(
            hasHeader(groupPosition),
            hasFooter(groupPosition), getChildrenCount(groupPosition)
        )
        if (groupPosition < mStructures.size) {
            mStructures.add(groupPosition, structure)
        } else {
            mStructures.add(structure)
            groupPosition = mStructures.size - 1
        }
        val index = countGroupRangeItem(0, groupPosition)
        val itemCount = countGroupItem(groupPosition)
        if (itemCount > 0) {
            notifyItemRangeInserted(index, itemCount)
            notifyItemRangeChanged(index + itemCount, getItemCount() - index)
        }
    }

    /**
     * 插入一组数据
     */
    @CallSuper
    open fun insertRangeGroup(groupPosition: Int, count: Int) {
        var groupPosition = groupPosition
        val list: ArrayList<GroupStructure> = ArrayList()
        for (i in groupPosition until count) {
            val structure = GroupStructure(
                hasHeader(i),
                hasFooter(i), getChildrenCount(i)
            )
            list.add(structure)
        }
        if (groupPosition < mStructures.size) {
            mStructures.addAll(groupPosition, list)
        } else {
            mStructures.addAll(list)
            groupPosition = mStructures.size - list.size
        }
        val index = countGroupRangeItem(0, groupPosition)
        val itemCount = countGroupRangeItem(groupPosition, count)
        if (itemCount > 0) {
            notifyItemRangeInserted(index, itemCount)
            notifyItemRangeChanged(index + itemCount, getItemCount() - index)
        }
    }

    /**
     * 插入组头
     */
    @CallSuper
    open fun insertHeader(groupPosition: Int) {
        if (groupPosition < mStructures.size && 0 > getPositionForGroupHeader(groupPosition)) {
            val structure = mStructures[groupPosition]
            structure.hasHeader = true
            val index = countGroupRangeItem(0, groupPosition)
            notifyItemInserted(index)
            notifyItemRangeChanged(index + 1, itemCount - index)
        }
    }

    /**
     * 插入组尾
     */
    @CallSuper
    open fun insertFooter(groupPosition: Int) {
        if (groupPosition < mStructures.size && 0 > getPositionForGroupFooter(groupPosition)) {
            val structure = mStructures[groupPosition]
            structure.hasFooter = true
            val index = countGroupRangeItem(0, groupPosition + 1)
            notifyItemInserted(index)
            notifyItemRangeChanged(index + 1, itemCount - index)
        }
    }

    /**
     * 插入一个子项到组里
     */
    fun insertChild(groupPosition: Int, childPosition: Int) {
        if (groupPosition < mStructures.size) {
            val structure = mStructures[groupPosition]
            var index = getPositionForChild(groupPosition, childPosition)
            if (index < 0) {
                index = countGroupRangeItem(0, groupPosition)
                index += if (structure.hasHeader) 1 else 0
                index += structure.childrenCount
            }
            structure.childrenCount = structure.childrenCount + 1
            notifyItemInserted(index)
            notifyItemRangeChanged(index + 1, itemCount - index)
        }
    }

    /**
     * 插入一组里的多个子项
     */
    @CallSuper
    open fun insertRangeChild(groupPosition: Int, childPosition: Int, count: Int) {
        if (groupPosition < mStructures.size) {
            var index = countGroupRangeItem(0, groupPosition)
            val structure = mStructures[groupPosition]
            if (structure.hasHeader) {
                index++
            }
            index += if (childPosition < structure.childrenCount) {
                childPosition
            } else {
                structure.childrenCount
            }
            if (count > 0) {
                structure.childrenCount = structure.childrenCount + count
                notifyItemRangeInserted(index, count)
                notifyItemRangeChanged(index + count, itemCount - index)
            }
        }
    }

    /**
     * 插入一组里的所有子项
     */
    fun insertChildren(groupPosition: Int) {
        if (groupPosition < mStructures.size) {
            var index = countGroupRangeItem(0, groupPosition)
            val structure = mStructures[groupPosition]
            if (structure.hasHeader) {
                index++
            }
            val itemCount: Int = getChildrenCount(groupPosition)
            if (itemCount > 0) {
                structure.childrenCount = itemCount
                notifyItemRangeInserted(index, itemCount)
                notifyItemRangeChanged(index + itemCount, getItemCount() - index)
            }
        }
    }

    //****** 设置点击事件 *****//

    //****** 设置点击事件 *****//
    /**
     * 设置组头点击事件
     *
     * @param listener
     */
    fun setOnHeaderClickListener(listener: OnHeaderClickListener<T>) {
        mOnHeaderClickListener = listener
    }

    /**
     * 设置组尾点击事件
     *
     * @param listener
     */
    fun setOnFooterClickListener(listener: OnFooterClickListener<T>) {
        mOnFooterClickListener = listener
    }

    /**
     * 设置子项点击事件
     *
     * @param listener
     */
    fun setOnChildClickListener(listener: OnChildClickListener<T>) {
        mOnChildClickListener = listener
    }

    abstract fun getGroupCount(): Int

    abstract fun getChildrenCount(groupPosition: Int): Int

    abstract fun hasHeader(groupPosition: Int): Boolean

    abstract fun hasFooter(groupPosition: Int): Boolean

    abstract fun getHeaderLayout(viewType: Int): Int

    abstract fun getFooterLayout(viewType: Int): Int

    abstract fun getChildLayout(viewType: Int): Int

    abstract fun onBindHeaderViewHolder(
        holder: HelperRecyclerViewHolder,
        groupPosition: Int,
        item: T
    )

    abstract fun onBindFooterViewHolder(
        holder: HelperRecyclerViewHolder,
        groupPosition: Int,
        item: T
    )

    abstract fun onBindChildViewHolder(
        holder: HelperRecyclerViewHolder,
        groupPosition: Int, childPosition: Int, item: T
    )

    inner class GroupDataObserver : RecyclerView.AdapterDataObserver() {
        override fun onChanged() {
            isDataChanged = true
        }

        override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
            isDataChanged = true
        }

        override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
            onItemRangeChanged(positionStart, itemCount)
        }

        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            isDataChanged = true
        }

        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
            isDataChanged = true
        }
    }

    interface OnHeaderClickListener<T> {
        fun onHeaderClick(
            adapter: GroupedRecyclerViewAdapter<*>,
            holder: HelperRecyclerViewHolder,
            groupPosition: Int,
            item: T
        )
    }

    interface OnFooterClickListener<T> {
        fun onFooterClick(
            adapter: GroupedRecyclerViewAdapter<*>,
            holder: HelperRecyclerViewHolder,
            groupPosition: Int,
            item: T
        )
    }

    interface OnChildClickListener<T> {
        fun onChildClick(
            adapter: GroupedRecyclerViewAdapter<*>, holder: HelperRecyclerViewHolder,
            groupPosition: Int, childPosition: Int, item: T
        )
    }
}